/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.karol.lx.distributor;

import java.util.concurrent.LinkedBlockingQueue;
import org.karol.lx.grader.StandardGraderInterface;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.karol.lx.fetcher.RequestReceiver;
import org.karol.lx.model.GradeRequest;

/**
 * Kelas singleton RequestDispatcher. Menerima antrian dari RequestReceiver dan
 * melepaskannya ke Agent
 *
 * @author karol
 */
public class WorkDistributor implements Runnable, RequestReceiver {

    private static WorkDistributor instance = null;
    private Thread mMainThread;
    private LinkedBlockingQueue<GradeRequest> mRequestQueue;
    private GraderSelector mSelector = null;

    private WorkDistributor() {
        mMainThread = new Thread(this);
        mRequestQueue = new LinkedBlockingQueue<GradeRequest>();
    }

    @Override
    public void addRequest(GradeRequest pRequest) {
        try {
            mRequestQueue.put(pRequest);
        } catch (InterruptedException ex) {
            Logger.getLogger(WorkDistributor.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static synchronized WorkDistributor getInstance() {
        if (instance == null) {
            instance = new WorkDistributor();
        }
        return instance;
    }

    public void main() {
        if (!mMainThread.isAlive()) {
            mMainThread.start();
        }
    }

    protected synchronized void processRequestQueue() {
        while (true) {
            try {
                GradeRequest tRequest = mRequestQueue.take();
                Logger.getLogger(WorkDistributor.class.getName()).log(Level.INFO, "Receiving {0}", tRequest);
                dispatchRequest(tRequest);
            } catch (InterruptedException ex) {
                Logger.getLogger(WorkDistributor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    protected void dispatchRequest(GradeRequest pRequest) {
        boolean found = false;

        while (!found) {
            StandardGraderInterface tAgent = mSelector.getSelectedGrader();
            
            if (tAgent != null) {
                tAgent.setReceiver(this);
                found = tAgent.offerRequest(pRequest);
            }

            if (!found) {
                //Logger.getLogger(WorkDistributor.class.getName()).log(Level.INFO, "No suitable grader found. Waiting");
                try {
                    Thread.sleep(50);
                } catch (InterruptedException ex) {
                    Logger.getLogger(WorkDistributor.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
    
    public void setGraderSelector(GraderSelector pSelector) {
        mSelector = pSelector;
    }

    @Override
    public void run() {
        processRequestQueue();
    }
}